package com.quanyan.place.service.impl;


import com.alibaba.fastjson.JSON;
import com.quanyan.api.APIResponse;
import com.quanyan.common.constants.Constants;
import com.quanyan.common.utils.BeanCopierUtils;
import com.quanyan.common.utils.DateTimeUtils;
import com.quanyan.common.utils.DateUtils;
import com.quanyan.common.utils.StringUtil;
import com.quanyan.place.constants.PlaceConstants;
import com.quanyan.place.entity.*;
import com.quanyan.place.entity.apireq.ReqPlaceCreateCombinedUnit;
import com.quanyan.place.entity.apireq.ReqPlaceDeleteCombinedUnit;
import com.quanyan.place.entity.apireq.ReqPlaceOrderListVo;
import com.quanyan.place.entity.apireq.ReqPlaceUpdateCombinedUnit;
import com.quanyan.place.entity.apiresp.*;
import com.quanyan.place.entity.vo.PlaceCombinedUnitVo;
import com.quanyan.place.entity.vo.PlaceUnitSalePlan;
import com.quanyan.place.entity.vo.PlaceUnitSalePlanVo;
import com.quanyan.place.mapper.*;

import org.apache.commons.collections.CollectionUtils;
import org.apache.xmlbeans.impl.xb.xsdschema.Public;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.quanyan.place.service.PlaceUnitCombineService;
import com.quanyan.place.utils.PlaceUtil;

import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.quanyan.place.constants.PlaceConstants.*;

/**
 * Created by yuanxuebing on 16/11/14.
 */
@Service("PlaceUnitCombineService")
public class PlaceUnitCombineServiceImpl implements PlaceUnitCombineService {
    private static final Logger logger = LoggerFactory.getLogger(PlaceUnitCombineServiceImpl.class);

    @Autowired
    TbBizPlaceUnitMapper puMapper;

    @Autowired
    TbBizPlaceUnitCombineMapper pucMapper;

    @Autowired
    TbBizPlaceUnitSalePlanMainMapper puspmMapper;

    @Autowired
    TbBizPlaceUnitSalePlanMapper puspMapper;

    @Autowired
    VPlaceMapper vPlaceMapper;

    @Override
    public APIResponse getCombinedUnitById(Integer cuId) {
        TbBizPlaceUnitCombine unit = pucMapper.selectByPrimaryKey(cuId);
        if (unit == null) {
            APIResponse.returnFail("无法获取该id的组合场地信息");
        }
        PlaceCombinedUnitVo placeCombinedUnitVo = newPlaceUnitCombine(unit, null, true);
        return APIResponse.returnSuccess(placeCombinedUnitVo);
    }

    @Override
    public APIResponse listCombinedUnits(Integer placeId, Integer cateId) {
        TbBizPlaceUnitCombineExample example = new TbBizPlaceUnitCombineExample();
        TbBizPlaceUnitCombineExample.Criteria criterial = example.createCriteria();
        if (placeId != null) {
            criterial.andPlaceIdEqualTo(placeId);
        }
        if (cateId != null) {
            criterial.andCategoryIdEqualTo(cateId.byteValue());
        }
        criterial.andIsDeleteEqualTo((byte) 0);

        List<PlaceCombinedUnitVo> pcus = new ArrayList<>();
        List<TbBizPlaceUnitCombine> units = pucMapper.selectByExample(example);
        for (TbBizPlaceUnitCombine tpcu : units) {
            pcus.add(newPlaceUnitCombine(tpcu, null, true));
        }

        return APIResponse.returnSuccess(pcus);
    }

    // 需要查组合表和基本单元表
    @Override
    public APIResponse listUncombinedSubUnits(Integer placeId, Integer cateId, String scale) {
        List<PlaceCombinedUnitVo> pcus = new ArrayList<>();

        TbBizPlaceUnitCombineExample example1 = new TbBizPlaceUnitCombineExample();
        TbBizPlaceUnitCombineExample.Criteria criterial1 = example1.createCriteria();
        if (placeId != null) {
            criterial1.andPlaceIdEqualTo(placeId);
        }
        if (cateId != null) {
            criterial1.andCategoryIdEqualTo(cateId.byteValue());
        }
        if (scale != null) {
            criterial1.andFieldScaleEqualTo(scale);
        }
        criterial1.andIsDeleteEqualTo((byte) 0);
        criterial1.andIsCombineEqualTo((byte) 0);
        example1.setOrderByClause("name");

        List<TbBizPlaceUnitCombine> subUnits = pucMapper.selectByExample(example1);
        for (TbBizPlaceUnitCombine tpcu : subUnits) {
            pcus.add(newPlaceUnitCombine(tpcu, null, false));
        }

        TbBizPlaceUnitExample example2 = new TbBizPlaceUnitExample();
        TbBizPlaceUnitExample.Criteria criterial2 = example2.createCriteria();
        if (placeId != null) {
            criterial2.andPlaceIdEqualTo(placeId);
        }
        if (cateId != null) {
            criterial2.andCategoryIdEqualTo(cateId.byteValue());
        }
        if (scale != null) {
            criterial2.andFieldScaleEqualTo(scale);
        }
        criterial2.andIsSignEqualTo(IS_SIGN_YES);
        criterial2.andIsCombineEqualTo((byte) 0);

        List<TbBizPlaceUnit> baseUnits = puMapper.selectByExample(example2);
        for (TbBizPlaceUnit tpc : baseUnits) {
            pcus.add(newPlaceUnitCombine(tpc));
        }

        return APIResponse.returnSuccess(pcus);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public APIResponse createCombinedUnit(ReqPlaceCreateCombinedUnit req) throws Exception {
        if (req.getSubUnits() == null || req.getSubUnits().size() <= 0) {
            return APIResponse.returnFail("请先指定要组合的子场地! ");
        }
        Integer subUnitSize = req.getSubUnits().size();

        // 构造组合配置 例如:301881-1803-0+301882-1803-0
        String cr = combineRule(req);

        // 先判断能否组合
        if (!checkCombineRule(cr)) {
            return APIResponse.returnFail("组合规则不合理! ");
        }

        // 展开组合
        List<Integer> baseUnits = new ArrayList<Integer>();     // 所有组合的的基本场地
        List<Integer> combinedUnits = new ArrayList<>();  // 所有子组合场地
        List<Integer> allBaseUnitIds = expandCombine(req.getSubUnits(), baseUnits, combinedUnits);

        // 只能被组合一次
        if (baseUnits.size() > 0) {
            if (!checkSubUnitCombineStatus(req.getPlaceId(), req.getCategoryId(), baseUnits, UNIT_TYPE_BASE)) {
                return APIResponse.returnFail("某些基本单元已经被组合过了! ");
            }
        }
        if (combinedUnits.size() > 0) {
            if (!checkSubUnitCombineStatus(req.getPlaceId(), req.getCategoryId(), combinedUnits, UNIT_TYPE_COMBINE)) {
                return APIResponse.returnFail("某些子组合单元已经被组合过了! ");
            }
        }
        // 在场地表中插一个"隐藏的场地"
        TbBizPlaceUnit newBaseUnit = newTbBizPlaceUnit(req, cr, allBaseUnitIds);
        int ret = puMapper.insertSelective(newBaseUnit);
        if (ret < 1) {
            throw new Exception("写入数据库失败！");
        }
        Integer id = newBaseUnit.getId();

        // 在组合场地表中插入数据
        TbBizPlaceUnitCombine newUnit = newTbBizPlaceUnitCombine(newBaseUnit, cr, subUnitSize, allBaseUnitIds);
        newUnit.setId(id);  // 和基本场地表中的id保持一致
        ret = pucMapper.insertSelective(newUnit);
        if (ret < 1) {
            throw new Exception("写入数据库失败！");
        }

        // 标记基本子单元已组合
        if (baseUnits != null && baseUnits.size() > 0) {
            TbBizPlaceUnitExample example1 = new TbBizPlaceUnitExample();
            TbBizPlaceUnitExample.Criteria criteria1 = example1.createCriteria();
            criteria1.andIdIn(baseUnits);
            TbBizPlaceUnit pu = new TbBizPlaceUnit();
            pu.setIsCombine((byte) 1);
            puMapper.updateByExampleSelective(pu, example1);
        }

        // 标记子组合场地已组合
        if (combinedUnits != null && combinedUnits.size() > 0) {
            TbBizPlaceUnitCombineExample example2 = new TbBizPlaceUnitCombineExample();
            TbBizPlaceUnitCombineExample.Criteria criteria2 = example2.createCriteria();
            criteria2.andIdIn(combinedUnits);
            TbBizPlaceUnitCombine puc = new TbBizPlaceUnitCombine();
            puc.setIsCombine((byte) 1);
            pucMapper.updateByExampleSelective(puc, example2);
        }

        // 从数据库中读取写入的信息
        TbBizPlaceUnitCombine tbPUC = pucMapper.selectByPrimaryKey(id);
        return APIResponse.returnSuccess(newPlaceUnitCombine(tbPUC, null, true));
    }


    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public APIResponse deleteCombinedUnit(ReqPlaceDeleteCombinedUnit req) throws Exception {
        // 从数据库中读取组合场地信息
        TbBizPlaceUnitCombine unit = pucMapper.selectByPrimaryKey(req.getId());
        if (unit == null) {
            return APIResponse.returnFail("要删除的组合场地不存在! ");
        }

        if (unit.getIsDelete() == 1) {
            return APIResponse.returnFail("要组合场已经被删除过了,不要重复删除! ");
        }

        // 如果是更大的场地的子场地则,必须先删除父场地
        if (unit.getIsCombine() == 1) {
            return APIResponse.returnFail("子场地不能直接删除,先删除父组合场! ");
        }

        // 如果销售计划中还有锁定,预定等状态的销售计划是不是不应该被删除

        String cr = unit.getCombineRule();
        if (cr == null || cr.isEmpty()) {
            return APIResponse.returnFail("没有该场地的组合规则信息! ");
        }

        List<SubUnitRule> subUnitRules = decodeCombineRules(cr);
        if (subUnitRules == null || subUnitRules.size() < 2) {  // 任何一个组合场都是由2个以上的子场组合而来
            return APIResponse.returnFail("不合法的组合规则! ");
        }
        List<Integer> baseUnitIds = new ArrayList<Integer>();     // 所有组合的的基本场地
        List<Integer> combinedUnitIds = new ArrayList<>();        // 所有子组合场地
        for(SubUnitRule subRule : subUnitRules) {
            if (subRule.isCombinedUnit == 1) {
                combinedUnitIds.add(subRule.unitId);
            } else {
                baseUnitIds.add(subRule.unitId);
            }
        }

        // 先标记删除
        TbBizPlaceUnitCombine ucRecord = new TbBizPlaceUnitCombine();
        ucRecord.setId(unit.getId());
        ucRecord.setIsDelete((byte) 1);
        int ret = pucMapper.updateByPrimaryKeySelective(ucRecord);
        if (ret < 1) {
            throw new Exception("写入数据库失败！");
        }

        // 标记基本子单元未组合
        if (baseUnitIds != null && baseUnitIds.size() > 0) {
            TbBizPlaceUnitExample example1 = new TbBizPlaceUnitExample();
            TbBizPlaceUnitExample.Criteria criteria1 = example1.createCriteria();
            criteria1.andIdIn(baseUnitIds);
            TbBizPlaceUnit pu = new TbBizPlaceUnit();
            pu.setIsCombine((byte) 0);
            puMapper.updateByExampleSelective(pu, example1);
        }

        // 标记子组合场地未组合
        if (combinedUnitIds != null && combinedUnitIds.size() > 0) {
            TbBizPlaceUnitCombineExample example2 = new TbBizPlaceUnitCombineExample();
            TbBizPlaceUnitCombineExample.Criteria criteria2 = example2.createCriteria();
            criteria2.andIdIn(combinedUnitIds);
            TbBizPlaceUnitCombine puc = new TbBizPlaceUnitCombine();
            puc.setIsCombine((byte) 0);
            pucMapper.updateByExampleSelective(puc, example2);
        }

        // 更新销售计划模板和已存在的销售计划
        TbBizPlaceUnitSalePlanMain record = new TbBizPlaceUnitSalePlanMain();
        record.setIsEffective(Constants.BYTE_ZERO);
        TbBizPlaceUnitSalePlanMainExample example3 = new TbBizPlaceUnitSalePlanMainExample();
        TbBizPlaceUnitSalePlanMainExample.Criteria criteria3 = example3.createCriteria();
        criteria3.andPlaceIdEqualTo(req.getPlaceId());
        criteria3.andPlaceUnitIdEqualTo(req.getId());

        ret = puspmMapper.updateByExampleSelective(record, example3);
        // 如果没有定价此处ret == 0
        if (ret < 0) {
            throw new Exception("修改销售模板失败！");
        }

        //vPlaceMapper.updateSalePlanToInvalidate(req.getId(), (byte) 2);
        if (req.getId() != null) {
            vPlaceMapper.updateAllSalePlanToInvalidate(req.getId(), (byte) 2);
        }

        return APIResponse.returnSuccess();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public APIResponse updateCombinedUnit(ReqPlaceUpdateCombinedUnit req) throws Exception {
        TbBizPlaceUnitCombine ucRecord = new TbBizPlaceUnitCombine();
        ucRecord.setId(req.getId());

        ucRecord.setName(req.getName());
        ucRecord.setPlaceUnitType(req.getPlaceUnitType());
        ucRecord.setPlaceUnitTexture(req.getPlaceUnitTexture());
        ucRecord.setFieldScale(req.getFieldScale());

        int ret = pucMapper.updateByPrimaryKeySelective(ucRecord);
        if (ret < 0) {
            throw new Exception("修改组合场地信息失败！");
        }

        // 注意还要同时修改 场地表中的 同id的虚拟场地
        TbBizPlaceUnit unitRecord = new TbBizPlaceUnit();
        unitRecord.setId(req.getId());

        unitRecord.setName(req.getName());
        unitRecord.setPlaceUnitType(req.getPlaceUnitType());
        unitRecord.setPlaceUnitTexture(req.getPlaceUnitTexture());
        unitRecord.setFieldScale(req.getFieldScale());

        ret = puMapper.updateByPrimaryKeySelective(unitRecord);
        if (ret < 0) {
            throw new Exception("修改场地表中虚拟场地信息失败！");
        }

        // 如果修改名称同时还要修改销售计划模板和销售计划中的场地名称
        if (req.getId() != null && req.getName() != null) {
            vPlaceMapper.updateSalePlanMainUnitName(req.getId(), req.getName());
            vPlaceMapper.updateSalePlanUnitName(req.getId(), req.getName());
        }

        return APIResponse.returnSuccess();
    }

    @Override
    public APIResponse combinePlaceUnit(Integer placeId, Integer cateId, String scale, Long startDateMS, Long endDateMS,
                                        RespPlaceUnitSalePlanDetail placeUnitSalePlanVo) {

        List<RespPlaceUnitSalePlanByDay> dayDatas = placeUnitSalePlanVo.getPlaceUnitInfoVoList();
        if (dayDatas == null || dayDatas.size() <= 0) {
            placeUnitSalePlanVo.setPlaceUnitInfoVoList(null);
            return APIResponse.returnSuccess(placeUnitSalePlanVo);
        }

        // 先遍历一遍获取所有的基本场信息
        Set<Integer> uniqBaseUnitIds = new HashSet<>();
        for (RespPlaceUnitSalePlanByDay dayData : dayDatas) {
            if (dayData != null) {
                List<RespPlaceUnitInfoVo> unitInfos = dayData.getPlaceUnitList();
                if (unitInfos == null ||  unitInfos.size() <= 0) {
                    continue;
                }
                for (RespPlaceUnitInfoVo unitInfo : unitInfos) {
                    if (unitInfo == null) {
                        continue;
                    } else {
                        uniqBaseUnitIds.add(unitInfo.getRespPlaceUnitInfo().getId());
                    }
                }
            }
        }
        List<Integer> allBaseUnitIds = new ArrayList<>();
        allBaseUnitIds.addAll(uniqBaseUnitIds);
        if (allBaseUnitIds.size() <= 0) {
            return APIResponse.returnSuccess(placeUnitSalePlanVo);
        }
        // 需要知道场地规模,所以查询所有的场地信息
        Map<Integer, TbBizPlaceUnit> subUnitsMap = getSubUnits(placeId, cateId, allBaseUnitIds);
        if (subUnitsMap == null || subUnitsMap.size() != allBaseUnitIds.size()) {
            return APIResponse.returnFail("场地数据异常");
        }

        // 获取同一规模的所有场地组合, 需要注意的可能满足规模条件的也可能是个基本场
        List<PlaceCombinedUnitVo> cus = getCombinedUnits(placeId, cateId, scale);

        // 查所有可能组合场地的销售计划 unitId-date-startTime-endTime --> SalePlan
        Map<String, TbBizPlaceUnitSalePlan> spms = getSalePlans(placeId, cus, startDateMS, endDateMS);

        // 由基本单元的"库存"情况计算 组合场地的库存情况
        for (RespPlaceUnitSalePlanByDay dayData : dayDatas) {
            if (dayData == null) {
                continue;
            }
            List<RespPlaceUnitInfoVo> unitInfos = dayData.getPlaceUnitList();
            if (unitInfos == null ||  unitInfos.size() <= 0) {
                continue;
            }

            // uintId_Date_startTime_endTime --> RespPlaceUnitSalePlanVo
            Map<String, RespPlaceUnitSalePlanVo> timeUnitMap = new HashMap<>();
            List<String> allTimes = new LinkedList<>();
            Set<String> uniqTimes = new HashSet<>();

            // 按场地-时间段遍历展开
            List<RespPlaceUnitInfoVo> newUnitInfos = new ArrayList<>();

            for (RespPlaceUnitInfoVo unitInfo : unitInfos) {
                if (unitInfo == null) {
                    continue;
                }

                // 补充场地规模信息
                Integer unitId = unitInfo.getRespPlaceUnitInfo().getId();
                TbBizPlaceUnit theUnit = subUnitsMap.get(unitId);
                if (theUnit != null) {
                    unitInfo.getRespPlaceUnitInfo().setFieldScale(theUnit.getFieldScale());
                }
                // 基本场就满足规模要求的直接提取出来
                String theScale = unitInfo.getRespPlaceUnitInfo().getFieldScale();
                if (null != scale && scale.equals(theScale)) {
                    newUnitInfos.add(unitInfo);
                    continue;
                }

                List<RespPlaceUnitSalePlanVo> timeSalePlans = unitInfo.getPlaceUnitSalePlanList();
                if (timeSalePlans != null && timeSalePlans.size() > 0) {
                    for (RespPlaceUnitSalePlanVo timeSalePlan : timeSalePlans) {
                        RespPlaceUnitSalePlan salePlan = timeSalePlan.getRespPlaceUnitSalePlan();

                        String timeKey = String.format("%s_%s_%s", dayData.getDate(), salePlan.getStartTime(), salePlan.getEndTime());
                        String key = String.format("%d_%s", salePlan.getPlaceUnitId(), timeKey);
                        timeUnitMap.put(key, timeSalePlan);
                        if (!uniqTimes.contains(timeKey)) {
                            uniqTimes.add(timeKey);
                            allTimes.add(timeKey);  // list是为了保证顺序不变
                        }
                    }
                }
            }

            // 遍历组合场地
            for (PlaceCombinedUnitVo cu : cus) {
                // 构造场地计划
                RespPlaceUnitInfoVo newUnitInfo = new RespPlaceUnitInfoVo();
                newUnitInfo.setRespPlaceUnitInfo(newRespPlaceUnitInfo(cu));     // 组合场地
                List<RespPlaceUnitSalePlanVo> puspVos = new ArrayList<>();

                Integer bundleNo = 0;
                String lockMark = "";

                for (String timeKey: allTimes) {
                    bundleNo = 0;
                    boolean available = true;
                    String[] parts = timeKey.split("_");
                    String date = parts[0];
                    String startTime = parts[1];
                    String endTime = parts[2];

                    // 如果没有获取的组合场的子场信息直接跳过
                    if (cu.getBaseUnitIds() == null || cu.getBaseUnitIds().size() <= 0) {
                        available = false;
                    } else {
                        for (Integer uid : cu.getBaseUnitIds()) {
                            String key = String.format("%d_%s", uid, timeKey);
                            if (!timeUnitMap.containsKey(key)) {
                                available = false;
                                break;
                            }

                            RespPlaceUnitSalePlanVo salePlanVo = timeUnitMap.get(key);
                            if (salePlanVo == null) {
                                available = false;
                                break;
                            } else {
                                if (salePlanVo.getRespPlaceUnitSalePlan().getBundleNo() != 0) {
                                    bundleNo = salePlanVo.getRespPlaceUnitSalePlan().getBundleNo();
                                }
                                if (salePlanVo.getRespPlaceUnitSalePlan().getLockRemarks() != null) {
                                    lockMark = (lockMark + salePlanVo.getRespPlaceUnitSalePlan().getLockRemarks());
                                }

                                Byte status = salePlanVo.getRespPlaceUnitSalePlan().getStatus();
                                if (status != PLACE_PREORDER_STATUS) {
                                    available = false;
                                    break;
                                }
                            }
                        }
                    }

                    String key = salePlanKey(cu.getId(), date, startTime, endTime);
                    TbBizPlaceUnitSalePlan theSalePlan = spms.get(key);

                    RespPlaceUnitSalePlan pusp = new RespPlaceUnitSalePlan();

                    pusp.setPlaceId(placeId);
                    pusp.setDate(date);
                    pusp.setStartTime(startTime);
                    pusp.setEndTime(endTime);

                    if (available && theSalePlan != null) {
                        pusp.setSaleId(theSalePlan.getSaleId());
                        pusp.setPlaceUnitId(theSalePlan.getPlaceUnitId());
                        pusp.setDate(DateUtils.transferDateToString(theSalePlan.getDate()));
                        pusp.setStartTime(DateTimeUtils.timeToStr(theSalePlan.getStartTime()));
                        pusp.setEndTime(DateTimeUtils.timeToStr(theSalePlan.getEndTime()));
                        pusp.setPrice(theSalePlan.getPrice());
                        pusp.setMemberPrice(theSalePlan.getMemberPrice());
                        pusp.setLowestPrice(theSalePlan.getLowestPrice());

                        pusp.setLockRemarks(lockMark);
                        pusp.setBundleNo(bundleNo);

                        pusp.setStatus(PLACE_PREORDER_STATUS);
                    } else {
                        pusp.setStatus(PLACE_ORDER_STATUS);
                    }

                    RespPlaceUnitSalePlanVo puspVo = new RespPlaceUnitSalePlanVo();
                    puspVo.setRespPlaceUnitSalePlan(pusp);
                    // 订单信息怎么搞?
                    puspVos.add(puspVo);
                }

                newUnitInfo.setPlaceUnitSalePlanList(puspVos);
                newUnitInfos.add(newUnitInfo);
            }

            dayData.setPlaceUnitList(newUnitInfos);

        }
        logger.warn("组合销售：{}", JSON.toJSONString(placeUnitSalePlanVo));
        return APIResponse.returnSuccess(placeUnitSalePlanVo);
    }

    /*
    fix 有两种情况 1 不可定子场地影响组合销售计划 2 组合销售计划
     */
    @Override
    public APIResponse fixPlaceUnitSalePlanDetail(RespPlaceUnitSalePlanDetail detail, List<TbBizPlaceUnitSalePlan> tbBizPlaceUnitSalePlanList) {
        List<RespPlaceUnitSalePlanByDay> dayDatas = detail.getPlaceUnitInfoVoList();
        if (dayDatas == null || dayDatas.size() <= 0) {
            return APIResponse.returnSuccess();
        }

        if (tbBizPlaceUnitSalePlanList == null) {
            return APIResponse.returnSuccess();
        }

        Map<String, TbBizPlaceUnitSalePlan> allSalePlanMap = new HashMap<>();
        for (TbBizPlaceUnitSalePlan tbSalePlan : tbBizPlaceUnitSalePlanList) {
            if (tbSalePlan != null && tbSalePlan.getSaleId() != null) {
                allSalePlanMap.put(tbSalePlan.getSaleId(), tbSalePlan);
            }
        }

        // 先遍历一遍获取所有的基本场信息
        for (RespPlaceUnitSalePlanByDay dayData : dayDatas) {
            if (dayData != null) {
                List<RespPlaceUnitInfoVo> unitInfos = dayData.getPlaceUnitList();
                if (unitInfos == null ||  unitInfos.size() <= 0) {
                    continue;
                }

                Set<String> disabledSubSalePlans = new HashSet<>();

                for (RespPlaceUnitInfoVo unitInfo : unitInfos) {
                    if (unitInfo == null || unitInfo.getPlaceUnitSalePlanList() == null) {
                        continue;
                    }

                    List<RespPlaceUnitSalePlanVo> newSalePlanList = new ArrayList<>();

                    for (RespPlaceUnitSalePlanVo salePlanVo : unitInfo.getPlaceUnitSalePlanList()) {
                        RespPlaceUnitSalePlan salePlan = salePlanVo.getRespPlaceUnitSalePlan();
                        if (salePlan != null && salePlan.getSaleId() != null) {
                            String saleId = salePlan.getSaleId();
                            TbBizPlaceUnitSalePlan tbSalePlan = allSalePlanMap.get(saleId);
                            if (tbSalePlan == null) {
                                continue;
                            }

                            if (UNIT_TYPE_BASE.equals(tbSalePlan.getUnitType())) {
                                newSalePlanList.add(salePlanVo);
                                continue;
                            }

                            // 所有的子销售计划
                            String subSaleplans = tbSalePlan.getSubSaleplans();
                            List<String> subSaleplanIds = new ArrayList<>();
                            if (subSaleplans != null) {
                                subSaleplanIds = Arrays.asList(subSaleplans.split("[|]"));
                            }

                            // 被预定,付款,锁定的组合销售计划
                            if (!PLACE_PREORDER_STATUS.equals(tbSalePlan.getStatus())) {
                                newSalePlanList.add(salePlanVo);
                                disabledSubSalePlans.addAll(subSaleplanIds);    // 子销售计划要被屏蔽
                                continue;
                            }

                            // 没有找到子销售计划的直接屏蔽
                            if (subSaleplanIds == null || subSaleplanIds.size() <= 0) {
                                continue;
                            }

                            Boolean canLock = true;
                            for (String salePlanId : subSaleplanIds) {
                                TbBizPlaceUnitSalePlan tbSubSalePlan = allSalePlanMap.get(salePlanId);
                                if (tbSubSalePlan == null) {
                                    canLock = false;
                                    break;
                                }

                                if (!PLACE_PREORDER_STATUS.equals(tbSubSalePlan.getStatus())) {
                                    canLock = false;
                                    break;
                                }
                            }

                            if (canLock) {
                                newSalePlanList.add(salePlanVo);
                            }
                        }
                    }

                    unitInfo.setPlaceUnitSalePlanList(newSalePlanList);
                }

                // 屏蔽被组合销售计划影响的单位场地
                if (disabledSubSalePlans.size() > 0) {
                    for (RespPlaceUnitInfoVo unitInfo : unitInfos) {
                        if (unitInfo == null || unitInfo.getPlaceUnitSalePlanList() == null) {
                            continue;
                        }

                        List<RespPlaceUnitSalePlanVo> newSalePlanList = new ArrayList<>();

                        for (RespPlaceUnitSalePlanVo salePlanVo : unitInfo.getPlaceUnitSalePlanList()) {
                            RespPlaceUnitSalePlan salePlan = salePlanVo.getRespPlaceUnitSalePlan();
                            if (salePlan != null && salePlan.getSaleId() != null) {
                                String saleId = salePlan.getSaleId();
                                if (!disabledSubSalePlans.contains(saleId)) {
                                    newSalePlanList.add(salePlanVo);
                                }
                            }
                        }

                        unitInfo.setPlaceUnitSalePlanList(newSalePlanList);
                    }
                }
            }
        }

        return APIResponse.returnSuccess();
    }

    // 从组合场地表中获取指定场馆-类别-规模的组合场地
    @Override
    public List<PlaceCombinedUnitVo> getCombinedUnits(Integer placeId, Integer cateId, String scale) {
        TbBizPlaceUnitCombineExample example = new TbBizPlaceUnitCombineExample();
        TbBizPlaceUnitCombineExample.Criteria criterial = example.createCriteria();
        if (placeId != null) {
            criterial.andPlaceIdEqualTo(placeId);
        }
        if (cateId != null) {
            criterial.andCategoryIdEqualTo(cateId.byteValue());
        }
        if (scale != null) {
            criterial.andFieldScaleEqualTo(scale);
        }
        criterial.andIsDeleteEqualTo((byte) 0); // 有效的组合场

        List<PlaceCombinedUnitVo> pcus = new ArrayList<>();
        List<TbBizPlaceUnitCombine> units = pucMapper.selectByExample(example);
        if (units != null && units.size() > 0) {
            for (TbBizPlaceUnitCombine tpcu : units) {
                pcus.add(newPlaceUnitCombine(tpcu, null, false));
            }
        }

        return pcus;
    }

    public String salePlanKey(Integer placeUnitId, String date, String startTime, String endTime) {
        return String.format("%d_%s_%s_%s", placeUnitId, date, startTime, endTime);
    }

    public String salePlanKey(Integer placeUnitId, Date date, Date startTime, Date endTime) {
        return String.format("%d_%s_%s_%s",
                placeUnitId,
                DateUtils.transferDateToString(date),                  /*YYYY-MM-DD*/
                DateTimeUtils.timeToStr(startTime),                    /*HH:MM*/
                DateTimeUtils.timeToStr(endTime));                     /*HH:MM*/
    }

    // key -> salePlanMain
    public Map<String, TbBizPlaceUnitSalePlan> getSalePlans(Integer placeId, List<PlaceCombinedUnitVo> cus, Long startTimeMS, Long endTimeMS) {
        Map<String, TbBizPlaceUnitSalePlan> result = new HashMap<>();

        List<Integer> cuids = new ArrayList<>();
        for (PlaceCombinedUnitVo cu : cus) {
            cuids.add(cu.getId());
        }
        if (cuids == null || cuids.size() <= 0) {
            return result;
        }

        TbBizPlaceUnitSalePlanExample example = new TbBizPlaceUnitSalePlanExample();
        TbBizPlaceUnitSalePlanExample.Criteria criterial = example.createCriteria();
        criterial.andPlaceIdEqualTo(placeId);
        criterial.andPlaceUnitIdIn(cuids);

        Date startDate = DateUtils.transferLongToDate(startTimeMS);
        Date endDate = DateUtils.transferLongToDate(endTimeMS);
        if (startDate.equals(endDate)) {
            criterial.andDateEqualTo(startDate);
        } else {
            criterial.andDateBetween(startDate, endDate);
        }

        List<TbBizPlaceUnitSalePlan> salePlans = puspMapper.selectByExample(example);
        if (salePlans != null && salePlans.size() > 0) {
            for (TbBizPlaceUnitSalePlan salePlan : salePlans) {
                String key = salePlanKey(salePlan.getPlaceUnitId(), salePlan.getDate(), salePlan.getStartTime(), salePlan.getEndTime());
                result.put(key, salePlan);
            }
        }

        return result;
    }

    public Map<Integer, TbBizPlaceUnit> getSubUnits(Integer placeId, Integer cateId, List<Integer> baseUintIds) {
        Map<Integer, TbBizPlaceUnit> result = new HashMap<>();

        TbBizPlaceUnitExample example = new TbBizPlaceUnitExample();
        TbBizPlaceUnitExample.Criteria criterial = example.createCriteria();
        if (placeId != null) {
            criterial.andPlaceIdEqualTo(placeId);
        }
        if (cateId != null) {
            criterial.andCategoryIdEqualTo(cateId.byteValue());
        }
        if (baseUintIds != null && baseUintIds.size() > 0) {
            criterial.andIdIn(baseUintIds);
        } else {
            return result;
        }

        List<TbBizPlaceUnit> baseUnits = puMapper.selectByExample(example);
        if (baseUnits != null && baseUnits.size() > 0) {
            for (TbBizPlaceUnit tpc : baseUnits) {
                result.put(tpc.getId(), tpc);
            }
        }

        return result;
    }

    public PlaceCombinedUnitVo newPlaceUnitCombine(TbBizPlaceUnitCombine tbPUC, Integer unitId, boolean needSubUnits) {
        if (tbPUC == null) {
            if (unitId == null) {
                return null;
            } else {
                tbPUC = pucMapper.selectByPrimaryKey(unitId);
            }
        }

        if (tbPUC == null) {
            return null;
        }

        PlaceCombinedUnitVo pcu = new PlaceCombinedUnitVo();
        BeanCopierUtils.copyProperties(tbPUC, pcu);
        pcu.setIsCombinedUnit((byte) 1);
        pcu.setBaseUnitIds(PlaceUtil.splitIds(tbPUC.getBaseUnits()));

        //还要读取子场地信息
        if (needSubUnits) {
            List<PlaceCombinedUnitVo> subUnitVos = new ArrayList<>();

            List<SubUnitRule> subUnitRules = decodeCombineRules(tbPUC.getCombineRule());
            List<Integer> baseUnitIds = new ArrayList<Integer>();     // 所有组合的的基本场地
            List<Integer> combinedUnitIds = new ArrayList<>();  // 所有子组合场地
            for(SubUnitRule subRule : subUnitRules) {
                if (subRule.isCombinedUnit == 1) {
                    combinedUnitIds.add(subRule.unitId);
                } else {
                    baseUnitIds.add(subRule.unitId);
                }
            }

            if (baseUnitIds.size() > 0) {
                List<PlaceCombinedUnitVo> baseUnitVos = new ArrayList<>();

                TbBizPlaceUnitExample example = new TbBizPlaceUnitExample();
                TbBizPlaceUnitExample.Criteria criterial = example.createCriteria();
                criterial.andIdIn(baseUnitIds);
                List<TbBizPlaceUnit> baseUnits = puMapper.selectByExample(example);
                for (TbBizPlaceUnit tpc : baseUnits) {
                    baseUnitVos.add(newPlaceUnitCombine(tpc));
                }
                subUnitVos.addAll(baseUnitVos);
            }

            if (combinedUnitIds.size() > 0) {
                List<PlaceCombinedUnitVo> combinedUnitVos = new ArrayList<>();
                for (Integer cuId : combinedUnitIds) {
                    PlaceCombinedUnitVo scuVo = newPlaceUnitCombine(null, cuId, needSubUnits);
                    if (scuVo != null) {
                        combinedUnitVos.add(scuVo);
                    }
                }
                subUnitVos.addAll(combinedUnitVos);
            }

            pcu.setSubUnits(subUnitVos);
        }

        return pcu;
    }

    public PlaceCombinedUnitVo newPlaceUnitCombine(TbBizPlaceUnit tbPU) {
        PlaceCombinedUnitVo pcu = new PlaceCombinedUnitVo();

        BeanCopierUtils.copyProperties(tbPU, pcu);
        pcu.setIsCombinedUnit((byte) 0);
        List<Integer> baseIds = new ArrayList<>();
        baseIds.add(tbPU.getId());
        pcu.setBaseUnitIds(baseIds);

        return pcu;
    }

    public TbBizPlaceUnit newTbBizPlaceUnit(ReqPlaceCreateCombinedUnit req, String combineRule, List<Integer> allBaseUnitIds) {
        //从数据库中读取基本场地信息
        Integer placeId = req.getPlaceId();
        Byte cateId = req.getCategoryId();

        TbBizPlaceUnitExample example = new TbBizPlaceUnitExample();
        TbBizPlaceUnitExample.Criteria criterial = example.createCriteria();
        if (placeId != null) {
            criterial.andPlaceIdEqualTo(placeId);
        }
        if (cateId != null) {
            criterial.andCategoryIdEqualTo(cateId);
        }
        criterial.andIdIn(allBaseUnitIds);
        List<TbBizPlaceUnit> pus = puMapper.selectByExample(example);
        TbBizPlaceUnit pu = null;
        if (pus != null && pus.size() > 0) {
            pu = pus.get(0);
        }

        TbBizPlaceUnit newUnit = new TbBizPlaceUnit();
        newUnit.setPlaceId(req.getPlaceId());
        newUnit.setName(req.getName());
        //newUnit.setExtendName();
        //newUnit.setComment();
        newUnit.setCategoryId(req.getCategoryId());
        newUnit.setFieldScale(req.getFieldScale());

        // 关于场地属性-如灯光、场地材质等信息可以从场地单元表中获取
        newUnit.setPlaceUnitType(pu.getPlaceUnitType());
        newUnit.setPlaceUnitTexture(pu.getPlaceUnitTexture());
        newUnit.setLightType(pu.getLightType());

        newUnit.setIsDelete((byte) 1);
        newUnit.setIsSign((byte) 0);

        newUnit.setIsCombine((byte) 0);

        return newUnit;
    }

    public TbBizPlaceUnitCombine newTbBizPlaceUnitCombine(TbBizPlaceUnit tbUnit,
                                                          String combineRule, Integer subUnitSize,
                                                          List<Integer> allBaseUnitIds) {

        TbBizPlaceUnitCombine newUnit = new TbBizPlaceUnitCombine();
        BeanCopierUtils.copyProperties(tbUnit, newUnit);

        newUnit.setIsDelete((byte) 0);
        newUnit.setIsCombine((byte) 0);
        newUnit.setCombineRule(combineRule);
        newUnit.setBaseUnits(PlaceUtil.joinIds(allBaseUnitIds));
        newUnit.setSubunitNum(subUnitSize);
        newUnit.setBaseunitNum(allBaseUnitIds.size());

        return newUnit;
    }

    // 组合场地信息构造一个场地信息
    public RespPlaceUnitInfo newRespPlaceUnitInfo(PlaceCombinedUnitVo unitVo) {
        RespPlaceUnitInfo pui = new RespPlaceUnitInfo();

        pui.setId(unitVo.getId());
        pui.setPlaceId(unitVo.getPlaceId());
        pui.setName(unitVo.getName());
        pui.setCategoryId(unitVo.getCategoryId());

        pui.setPlaceUnitType(unitVo.getPlaceUnitType());
        pui.setPlaceUnitTexture(unitVo.getPlaceUnitTexture());
        pui.setLightType(unitVo.getLightType());
        pui.setFieldScale(unitVo.getFieldScale());

        return pui;
    }

    // 将组合展开成基本单元的集合
    public List<Integer> expandCombine(List<PlaceCombinedUnitVo> subUnits, List<Integer> baseUnitIds, List<Integer> combinedUnitIds) {
        List<Integer> allbaseIds = new LinkedList<>();

        for (PlaceCombinedUnitVo su : subUnits) {
            if (su.getIsCombinedUnit() == 0) {
                baseUnitIds.add(su.getId());
            } else if (su.getIsCombinedUnit() == 1) {
                combinedUnitIds.add(su.getId());
            }

            // 如果前端已经带过来的,则使用前端的数据
            List<Integer> curBaseUnitIds = new ArrayList<>();
            if (su.getBaseUnitIds() != null && su.getBaseUnitIds().size() > 0) {
                curBaseUnitIds = su.getBaseUnitIds();
            } else {
                if (su.getIsCombinedUnit() == 0) {
                    curBaseUnitIds.add(su.getId());
                } else if (su.getIsCombinedUnit() == 1) {
                    // 从数据库中读取
                    TbBizPlaceUnitCombine tbPUC = pucMapper.selectByPrimaryKey(su.getId());
                    curBaseUnitIds = PlaceUtil.splitIds(tbPUC.getBaseUnits());
                }
            }

            allbaseIds.addAll(curBaseUnitIds);
        }

        return allbaseIds;
    }

    // 检查要组合的"子单元"是否都没有还没被组合过
    public boolean checkSubUnitCombineStatus(Integer placeId, Byte cateId, List<Integer> subUnitIds, Byte unitType) {
        int count = -1;

        if (UNIT_TYPE_BASE.equals(unitType)) {
            TbBizPlaceUnitExample example = new TbBizPlaceUnitExample();
            TbBizPlaceUnitExample.Criteria criterial = example.createCriteria();
            if (placeId != null) {
                criterial.andPlaceIdEqualTo(placeId);
            }
            if (cateId != null) {
                criterial.andCategoryIdEqualTo(cateId);
            }
            criterial.andIdIn(subUnitIds);
            criterial.andIsCombineEqualTo((byte) 0);
            count = puMapper.countByExample(example);
        } else if (UNIT_TYPE_COMBINE.equals(unitType)) {
            TbBizPlaceUnitCombineExample example = new TbBizPlaceUnitCombineExample();
            TbBizPlaceUnitCombineExample.Criteria criterial = example.createCriteria();
            if (placeId != null) {
                criterial.andPlaceIdEqualTo(placeId);
            }
            if (cateId != null) {
                criterial.andCategoryIdEqualTo(cateId);
            }
            criterial.andIdIn(subUnitIds);
            criterial.andIsCombineEqualTo((byte) 0);
            count = pucMapper.countByExample(example);
        }

        if (count >= subUnitIds.size()) {
            return true;
        }

        return false;
    }

    class SubUnitRule {
        public Integer unitId;
        public String fieldScale;
        public Byte isCombinedUnit;

        public SubUnitRule() {

        }

        public SubUnitRule(Integer unitId, String fieldScale, Byte isCombinedUnit) {
            this.unitId = unitId;
            this.fieldScale = fieldScale;
            this.isCombinedUnit = isCombinedUnit;
        }

        public String encode() {
            return String.format("%d-%s-%d", unitId, fieldScale, isCombinedUnit);
        }

        public boolean decode(String cr) {
            String[] parts = cr.split("-");
            if (parts == null || parts.length != 3) {
                return false;
            }
            unitId = Integer.valueOf(parts[0]);
            fieldScale = parts[1];
            isCombinedUnit = Byte.valueOf(parts[2]);

            return true;
        }
    }

    // 构造组合表达式
    public String combineRule(ReqPlaceCreateCombinedUnit req) {
        List<SubUnitRule> subUnitRules = new ArrayList<>();
        for (PlaceCombinedUnitVo subUnit : req.getSubUnits()) {
            if (subUnit != null) {
                SubUnitRule subRule = new SubUnitRule(subUnit.getId(), subUnit.getFieldScale(), subUnit.getIsCombinedUnit());
                subUnitRules.add(subRule);
            }
        }

        return encodeCombineRules(subUnitRules);
    }

    public String encodeCombineRules(List<SubUnitRule> rules) {
        
        List<String> RuleStrings = new ArrayList<>();
        for (SubUnitRule subUnit : rules) {
            RuleStrings.add(subUnit.encode());
        }

        return StringUtil.join("+", RuleStrings);
    }

    //
    public List<SubUnitRule> decodeCombineRules(String cr) {
        List<SubUnitRule> subRules = new ArrayList<>();

        String[] ruleStrings = cr.split("[+]");
        for(String ruleString : ruleStrings) {
            SubUnitRule subRule = new SubUnitRule();
            if (subRule.decode(ruleString)) {
                subRules.add(subRule);
            }
        }

        return subRules;
    }

    // 检查组合规则是否合理
    static public Boolean checkCombineRule(String combineRule) {
        // todo...
        return true;
    }

}
